/**
 * @author nttdocomo
 */
define(function(require) {
	require("./lang/event");
	require("./jquery.scrollIntoView");
	require("./jquery.support");
	$.support.borderRadius = false;
	$.each(['BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'], function() {
		if (document.body.style[this] !== undefined)
			$.support.borderRadius = true;
		return (!$.support.borderRadius);
	});
	var doc = document, win = window, initExtCss = function() {
		// find the body element
		var bd = doc.body || doc.getElementsByTagName('body')[0], baseCSSPrefix = aries.baseCSSPrefix, cls = [baseCSSPrefix + 'body'], htmlCls = [], html;

		if (!bd) {
			return false;
		}

		html = bd.parentNode;

		function add(c) {
			cls.push(baseCSSPrefix + c);
		}

		//Let's keep this human readable!
		if (aries.isIE) {
			add('ie');

			// very often CSS needs to do checks like "IE7+" or "IE6 or 7". To help
			// reduce the clutter (since CSS/SCSS cannot do these tests), we add some
			// additional classes:
			//
			//      x-ie7p      : IE7+      :  7 <= ieVer
			//      x-ie7m      : IE7-      :  ieVer <= 7
			//      x-ie8p      : IE8+      :  8 <= ieVer
			//      x-ie8m      : IE8-      :  ieVer <= 8
			//      x-ie9p      : IE9+      :  9 <= ieVer
			//      x-ie78      : IE7 or 8  :  7 <= ieVer <= 8
			//
			if (aries.isIE6) {
				add('ie6');
			} else {// ignore pre-IE6 :)
				add('ie7p');

				if (aries.isIE7) {
					add('ie7');
				} else {
					add('ie8p');

					if (aries.isIE8) {
						add('ie8');
					} else {
						add('ie9p');

						if (aries.isIE9) {
							add('ie9');
						}
					}
				}
			}

			if (aries.isIE6 || aries.isIE7) {
				add('ie7m');
			}
			if (aries.isIE6 || aries.isIE7 || aries.isIE8) {
				add('ie8m');
			}
			if (Ext.isIE7 || Ext.isIE8) {
				add('ie78');
			}
		}
		if (aries.isGecko) {
			add('gecko');
			if (aries.isGecko3) {
				add('gecko3');
			}
			if (aries.isGecko4) {
				add('gecko4');
			}
			if (aries.isGecko5) {
				add('gecko5');
			}
		}
		if (aries.isOpera) {
			add('opera');
		}
		if (aries.isWebKit) {
			add('webkit');
		}
		if (aries.isSafari) {
			add('safari');
			if (aries.isSafari2) {
				add('safari2');
			}
			if (aries.isSafari3) {
				add('safari3');
			}
			if (aries.isSafari4) {
				add('safari4');
			}
			if (aries.isSafari5) {
				add('safari5');
			}
			if (aries.isSafari5_0) {
				add('safari5_0')
			}
		}
		if (aries.isChrome) {
			add('chrome');
		}
		if (aries.isMac) {
			add('mac');
		}
		if (aries.isLinux) {
			add('linux');
		}
		if (!aries.supports.CSS3BorderRadius) {
			add('nbr');
		}
		if (!aries.supports.CSS3LinearGradient) {
			add('nlg');
		}
		if (!aries.scopeResetCSS) {
			add('reset');
		}

		// add to the parent to allow for selectors x-strict x-border-box, also set the isBorderBox property correctly
		if (html) {
			if (aries.isStrict && (aries.isIE6 || aries.isIE7)) {
				aries.isBorderBox = false;
			} else {
				aries.isBorderBox = true;
			}

			if (aries.isBorderBox) {
				htmlCls.push(baseCSSPrefix + 'border-box');
			}
			if (aries.isStrict) {
				htmlCls.push(baseCSSPrefix + 'strict');
			} else {
				htmlCls.push(baseCSSPrefix + 'quirks');
			}
			aries.fly(html, '_internal').addCls(htmlCls);
		}

		aries.fly(bd, '_internal').addCls(cls);
		return true;
	};
	function d(a, b) {
		var c = window, d = a.split(".");
		for (var e = 0, f = d.length; e < f; e++) {
			var g = d[e];
			typeof c[g] == "undefined" && (c[g] = {}), c = c[g]
		}
		if (b)
			for (var i in b)
			c[i] = b[i];
		return c
	};
	d("aries", {
		baseCSSPrefix : "g-",
		BLANK_IMAGE_URL : "",
		copyTo : function(dest, source, names, usePrototypeKeys) {
			if ( typeof names == "string") {
				names = names.split(/[,;\s]/);
			}
			var n, nLen = names.length, name;
			for ( n = 0; n < nLen; n++) {
				name = names[n];
				if (usePrototypeKeys || source.hasOwnProperty(name)) {
					dest[name] = source[name];
				}
			}
			return dest;
		},
		emptyFn : function() {
		},
		expando : false,
		filter : function(a, b, c) {
			var d;
			if ($.isArray(a)) {
				var e = [];
				for (var f = 0, g = a.length; f < g; ++f) {
					d = c ? b.call(c, a[f], f, a) : b(a[f], f, a);
					if (!d) {
						continue;
					}
					e.push(a[f]);
				}
				return e;
			}
			if (jQuery.isPlainObject(a)) {
				var h = {};
				for (var i in a) {
					d = c ? b.call(c, i, a[i], a) : b(i, a[i], a);
					if (!d) {
						continue;
					}
					h[i] = a[i];
				}
				return h;
			}
		},
		outerHtml : function(el) {
			var div = document.createElement("div");
			div.appendChild(el);
			return div.innerHTML;
		},
		isDefined : function(value) {
			return typeof value !== "undefined";
		},

		/**
		 * Returns true if the passed value is empty, false otherwise. The value is deemed to be empty if it is either:
		 *
		 * - `null`
		 * - `undefined`
		 * - a zero-length array
		 * - a zero-length string (Unless the `allowEmptyString` parameter is set to `true`)
		 *
		 * @param {Object} value The value to test
		 * @param {Boolean} allowEmptyString (optional) true to allow empty strings (defaults to false)
		 * @return {Boolean}
		 * @markdown
		 */
		isEmpty : function(value, allowEmptyString) {
			return (value === null) || (value === undefined) || ( allowEmptyString ? value === '' : false) || ($.isArray(value) && value.length === 0);
		},
		isSSL : function() {
			return aries.proto === "https";
		},
		mixin : function(oldProps, newProps) {
			for (var key in newProps) {
				if ( typeof oldProps[key] == 'undefined') {
					oldProps[key] = newProps[key]
				}
			}
		},
		name : "aries",
		proto : "https",
		provide : d,
		reduce : function(a, b, c) {
			return $.each(a, function(a, d) {
				b = c(b, a, d)
			}), b
		},
		$win : $(window),
		$doc : $(document),
		$body : $(document.body),
		at : function(a, b) {
			var c = a.split("."), d = b || window;
			while (c.length > 0) {
				d = d[c.shift()];
				if ( typeof d == "undefined") {
					return undefined;
				}
			}
			return d;
		},
		bind : function(E, D) {
			return function() {
				return D.apply(E, arguments)
			}
		},
		userAgent : navigator.userAgent.toLowerCase(),
		value : function(value, defaultValue, allowBlank) {
			return aries.isEmpty(value, allowBlank) ? defaultValue : value;
		}
	});
	(function() {
		var check = function(regex) {
			return regex.test(aries.userAgent);
		}, isIE = (function() {
			return jQuery.browser.msie
		})(), isIE6 = function() {
			return jQuery.browser.msie && jQuery.browser.version == "6.0"
		}(), isIE7 = function() {
			return jQuery.browser.msie && jQuery.browser.version == "7.0"
		}(), isIE8 = function() {
			return jQuery.browser.msie && jQuery.browser.version == "8.0"
		}(), isWebKit = check(/webkit/), isGecko = !isWebKit && check(/gecko/);
	})()
	aries.augmentObject = function(H, I) {
		var K;
		if ($.type(H) !== 'string') {
			K = H;
		} else {
			K = aries.augmentString(H, {})
		}
		for (var G in I) {
			K[G] = I[G]
		}
		return K
	};
	aries.aug = function() {
		return aries.augmentObject.apply({}, arguments)
	};
	aries.augmentString = function(L, J) {
		var K = window;
		var I = L.split(".");
		for (var H = 0, G = I.length; H < G; ++H) {
			K = K[I[H]] = K[I[H]] || (( typeof I[H + 1] !== "undefined") ? {} : J)
		}
		return K
	};
	aries.klass = function(name, prop) {
		var K = prop || Class.extend();
		var E = aries.augmentString(name, K);
		var g = name.split(".").pop();
		E._namespace = name;
		E._name = g;
		E.mixin = function(mixins) {
			for (name in mixins) {
				var c = mixins[name].prototype;
				aries.mixin(this.prototype, c);
				if (!this.prototype.mixins) {
					this.prototype.mixins = {}
				}
				this.prototype.mixins[name] = mixins[name]
			}
			return this;
		}
		return E
	};
	aries.view = function(name, cls) {
		var C = aries.klass(name, cls);
		C.template = function(F) {
			this._template = F;
			this.namespace = name;
			return this
		};
		aries.views._setDefaultTemplate(C, name);
		C._partials = aries.templates;
		return C
	};
	aries.views = {};
	aries.views._setDefaultTemplate = function(C, D, S) {
		var templateName = aries.util.underscore(D.replace(/(\w+?\.){2}/, "")).toLowerCase().replace(/\./g, "_");
		if (aries.templates && aries.templates[templateName]) {
			C.template(aries.templates[templateName])
		} else {
			var S = S ? S.__super__.constructor : C.__super__.constructor;
			if (S.namespace)
				aries.views._setDefaultTemplate(C, S.namespace, S)
		}
	};
	var F = /_(.)/g;
	aries.augmentObject('aries.util', {
		capitalize : function(str) {
			return str.charAt(0).toUpperCase() + str.substr(1)
		},
		camelize : function(str) {
			return str.replace(F, function(I, J) {
				return J.toUpperCase()
			})
		},
		diff : function(a, b, c) {
			var d = {};
			if (!jQuery.isPlainObject(a) || !jQuery.isPlainObject(b)) {
				throw new Error("util.diff currently supports only single-level object comparison");
			}
			for (var e in a) {
				c ? c(a[e], b[e]) || (d[e] = [a[e], b[e]]) : a[e] !== b[e] && (d[e] = [a[e], b[e]]);
			}
			for (var e in b) {
				d[e] || ( c ? c(b[e], a[e]) || (d[e] = [a[e], b[e]]) : a[e] !== b[e] && (d[e] = [a[e], b[e]]));
			}
			return d;
		},
		underscore : function(H) {
			if (H.toUpperCase() === H) {
				return H
			}
			return H.replace(/([a-zA-Z0-9])([A-Z])/g, function(I, K, J) {
				return (K + "_" + J)
			}).toLowerCase()
		},
		throttle : function throttle(fn, delay) {
			var timer = null;
			return function() {
				var context = this, args = arguments;
				clearTimeout(timer);
				timer = setTimeout(function() {
					fn.apply(context, args);
				}, delay);
			};
		},
		statusModelToJson : function(model) {
			var status_key = ["created_at", "favorited", "mid", "text"];
			var user_key = ["domain", "screen_name", "id", "profile_image_url", "name"];
			var json = {};
			for (var i = 0, len = status_key.length; i < len; i++) {
				json[status_key[i]] = model.get([status_key[i]]);
			}
			for (var i = 0, len = user_key.length; i < len; i++) {
				json[user_key[i]] = model.get('user').get([user_key[i]]);
			}
			return json;
		}
	});
	var formatRe = /\{(\d+)\}/g;
	aries.augmentObject('aries.String', {
		format : function(format) {
			var args = aries.Array.toArray(arguments, 1);
			return format.replace(formatRe, function(m, i) {
				return args[i];
			});
		}
	});
	aries.Class = function(options) {
		if (this.initialize)
			this.initialize.apply(this, arguments);
	};
	aries.Class.extend = Backbone.View.extend;
	/*var horizontalPositions = /left|center|right/, verticalPositions = /top|center|bottom/, center = "center", support = {}, _position = $.fn.position, _offset = $.fn.offset;
	$.fn.position = function(options) {
		if (!options || !options.of) {
			return _position.apply(this, arguments);
		}

		// make a copy, we don't want to modify arguments
		options = $.extend({}, options);

		var target = $(options.of), targetElem = target[0], collision = (options.collision || "flip" ).split(" "), offset = options.offset ? options.offset.split(" ") : [0, 0], targetWidth, targetHeight, basePosition;

		if (targetElem.nodeType === 9) {
			targetWidth = target.width();
			targetHeight = target.height();
			basePosition = {
				top : 0,
				left : 0
			};
			// TODO: use $.isWindow() in 1.9
		} else if (targetElem.setTimeout) {
			targetWidth = target.width();
			targetHeight = target.height();
			basePosition = {
				top : target.scrollTop(),
				left : target.scrollLeft()
			};
		} else if (targetElem.preventDefault) {
			// force left top to allow flipping
			options.at = "left top";
			targetWidth = targetHeight = 0;
			basePosition = {
				top : options.of.pageY,
				left : options.of.pageX
			};
		} else {
			targetWidth = target.outerWidth();
			targetHeight = target.outerHeight();
			basePosition = target.offset();
		}

		// force my and at to have valid horizontal and veritcal positions
		// if a value is missing or invalid, it will be converted to center
		$.each(["my", "at"], function() {
			var pos = (options[this] || "" ).split(" ");
			if (pos.length === 1) {
				pos = horizontalPositions.test(pos[0]) ? pos.concat([center]) : verticalPositions.test(pos[0]) ? [center].concat(pos) : [center, center];
			}
			pos[0] = horizontalPositions.test(pos[0]) ? pos[0] : center;
			pos[1] = verticalPositions.test(pos[1]) ? pos[1] : center;
			options[this] = pos;
		});

		// normalize collision option
		if (collision.length === 1) {
			collision[1] = collision[0];
		}

		// normalize offset option
		offset[0] = parseInt(offset[0], 10) || 0;
		if (offset.length === 1) {
			offset[1] = offset[0];
		}
		offset[1] = parseInt(offset[1], 10) || 0;

		if (options.at[0] === "right") {
			basePosition.left += targetWidth;
		} else if (options.at[0] === center) {
			basePosition.left += targetWidth / 2;
		}

		if (options.at[1] === "bottom") {
			basePosition.top += targetHeight;
		} else if (options.at[1] === center) {
			basePosition.top += targetHeight / 2;
		}

		basePosition.left += offset[0];
		basePosition.top += offset[1];

		return this.each(function() {
			var elem = $(this), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseInt($.curCSS(this, "marginLeft", true)) || 0, marginTop = parseInt($.curCSS(this, "marginTop", true)) || 0, collisionWidth = elemWidth + marginLeft + (parseInt($.curCSS(this, "marginRight", true)) || 0 ), collisionHeight = elemHeight + marginTop + (parseInt($.curCSS(this, "marginBottom", true)) || 0 ), position = $.extend({}, basePosition), collisionPosition;

			if (options.my[0] === "right") {
				position.left -= elemWidth;
			} else if (options.my[0] === center) {
				position.left -= elemWidth / 2;
			}

			if (options.my[1] === "bottom") {
				position.top -= elemHeight;
			} else if (options.my[1] === center) {
				position.top -= elemHeight / 2;
			}

			// prevent fractions if jQuery version doesn't support them (see #5280)
			if (!support.fractions) {
				position.left = Math.round(position.left);
				position.top = Math.round(position.top);
			}

			collisionPosition = {
				left : position.left - marginLeft,
				top : position.top - marginTop
			};

			$.each(["left", "top"], function(i, dir) {
				if ($.ui.position[collision[i]]) {
					$.ui.position[ collision[i] ][ dir ](position, {
						targetWidth : targetWidth,
						targetHeight : targetHeight,
						elemWidth : elemWidth,
						elemHeight : elemHeight,
						collisionPosition : collisionPosition,
						collisionWidth : collisionWidth,
						collisionHeight : collisionHeight,
						offset : offset,
						my : options.my,
						at : options.at
					});
				}
			});

			if ($.fn.bgiframe) {
				elem.bgiframe();
			}
			elem.offset($.extend(position, {
				using : options.using
			}));
		});
	};

	aries.augmentObject('$.ui', {
		position : {
			fit : {
				left : function(position, data) {
					var win = $(window), over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
					position.left = over > 0 ? position.left - over : Math.max(position.left - data.collisionPosition.left, position.left);
				},
				top : function(position, data) {
					var win = $(window), over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
					position.top = over > 0 ? position.top - over : Math.max(position.top - data.collisionPosition.top, position.top);
				}
			},

			flip : {
				left : function(position, data) {
					if (data.at[0] === center) {
						return;
					}
					var win = $(window), over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(), myOffset = data.my[0] === "left" ? -data.elemWidth : data.my[0] === "right" ? data.elemWidth : 0, atOffset = data.at[0] === "left" ? data.targetWidth : -data.targetWidth, offset = -2 * data.offset[0];
					position.left += data.collisionPosition.left < 0 ? myOffset + atOffset + offset : over > 0 ? myOffset + atOffset + offset : 0;
				},
				top : function(position, data) {
					if (data.at[1] === center) {
						return;
					}
					var win = $(window), over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(), myOffset = data.my[1] === "top" ? -data.elemHeight : data.my[1] === "bottom" ? data.elemHeight : 0, atOffset = data.at[1] === "top" ? data.targetHeight : -data.targetHeight, offset = -2 * data.offset[1];
					position.top += data.collisionPosition.top < 0 ? myOffset + atOffset + offset : over > 0 ? myOffset + atOffset + offset : 0;
				}
			}
		}
	});*/

	aries.augmentObject('$.fn', {
		addClsOnOver : function(className, testFn, scope) {
			var me = this, dom = me.dom, hasTest = _.isFunction(testFn);

			me.hover(function() {
				if (hasTest && testFn.call(scope || me, me) === false) {
					return;
				}
				me.addClass(className);
			}, function() {
				me.removeClass(className);
			});
			return me;
		},

		/**
		 * Sets up event handlers to add and remove a css class when the mouse is down and then up on this element (a click effect)
		 * @param {String} className The class to add
		 * @param {Function} [testFn] A test function to execute before adding the class. The passed parameter
		 * will be the Element instance. If this functions returns false, the class will not be added.
		 * @param {Object} [scope] The scope to execute the testFn in.
		 * @return {Ext.dom.Element} this
		 */
		addClsOnClick : function(className, testFn, scope) {
			var me = this, dom = me.dom, hasTest = _.isFunction(testFn);

			me.on("mousedown", function() {
				if (hasTest && testFn.call(scope || me, me) === false) {
					return false;
				}
				me.addClass(className);
				var d = $(document), fn = function() {
					me.removeClass(className);
					d.off("mouseup", fn);
				};
				d.on("mouseup", fn);
			});
			return me;
		}
	});
})